package com.simulation;

import java.util.ArrayList;
import java.util.List;

import sim.display.GUIState;

import com.database.bean.Agent;
import com.database.bean.AgentType;
import com.database.bean.CompanyProduct;
import com.database.bean.CompanyRoundDecisionAndResult;
import com.database.bean.Game;
import com.database.bean.Round;
import com.database.bean.Setting;
import com.database.bean.User;
import com.logic.service.AdminService;
import com.math.util.GaussianNumberGenerator;

public class SimulationEngine extends GUIState {

	public SimulationEngine() { // Constructor for this class
		super(new AgentsSimulation(System.currentTimeMillis()));
	}

	public AgentsSimulation getAgentSimulation(){
		return ((AgentsSimulation)this.state);
	}
	
	public void doSimulationSteps(Game game,Round round,int stepAmount) {
		for (int i=0;i<stepAmount;i++){
			doSimulationStep(game,round);
		}
	}

	public void doSimulationStep(Game game,Round round) {
		getAgentSimulation().setGame(game);
		setAllOfferedProductsInformation(game,round);
		this.start();
		this.step();
	}

	public List<Agent> getAgents() {
		return getAgentSimulation().getAgents();
	}

	public void setAgents(List<Agent> agents) {
		getAgentSimulation().setAgents(agents);
	}
	
	public void addAgent(Agent agent){
		getAgentSimulation().addAgent(agent);
	}

	public void addAgents(List<Agent> agents){
		getAgentSimulation().addAgents(agents);
	}
	
	public void setAdminService(AdminService adminService){
		AgentsSimulation as=getAgentSimulation();
		as.setAdminService(adminService);
	}
	
	public List<CompanyProduct> getAllOfferedProducts() {
		return getAgentSimulation().getAllOfferedProducts();
	}

	private void setAllOfferedProductsInformation(Game game,Round simulationRound) {
		//collect all offered products from all companies to the simulated round
		List<CompanyProduct> allOfferedProducts=new ArrayList<CompanyProduct>();
		List<CompanyRoundDecisionAndResult> companyDecisionsAndResults=simulationRound.getCompanyRoundDecisionAndResults();
		for(CompanyRoundDecisionAndResult companyDecisionsAndResult : companyDecisionsAndResults){
			List<CompanyProduct> offeredProducts=companyDecisionsAndResult.getCompanyProducts();
			
			for(CompanyProduct cp : offeredProducts){
				
				//just take companyproducts that have at least a selling price >= 1
				//to avoid default values 0 from users that have forgotten to set a price
				if(cp.getSellingPrice()>=1)				
					allOfferedProducts.add(cp);
			}
		}
		getAgentSimulation().setAllOfferedProducts(allOfferedProducts);
		
		
		if(allOfferedProducts.size()>0){
			Double maximumSellingPrice=null;
			Double minimumSellingPrice=null;
			Double minimumProductQuality=null;
			Double maximumProductQuality=null;
			//find out the product with the lowest costs for the reference price lowestPrice/actualPrice
			for(CompanyProduct companyProduct : allOfferedProducts){
				Double sellingPrice = companyProduct.getSellingPrice();
				Double quality=companyProduct.getProduct().getQualityFactor();
				
				if(minimumSellingPrice==null){
					minimumSellingPrice = sellingPrice;
				}
				else if(sellingPrice < minimumSellingPrice){
					minimumSellingPrice = sellingPrice;
				}
				
				if(maximumSellingPrice==null){
					maximumSellingPrice = sellingPrice;
				}
				else if(maximumSellingPrice < sellingPrice){
					maximumSellingPrice = sellingPrice;
				}
				
				if(minimumProductQuality==null){
					minimumProductQuality = quality;
				}
				else if(quality < minimumProductQuality){
					minimumProductQuality = quality;
				}
				
				if(maximumProductQuality==null){
					maximumProductQuality = quality;
				}
				else if(maximumProductQuality < quality){
					maximumProductQuality = quality;
				}
				
			}
			
			if(minimumProductQuality==null || minimumProductQuality<0.1)
				minimumProductQuality=0.1;
			
			getAgentSimulation().setMinimumSellingPrice(minimumSellingPrice);
			getAgentSimulation().setMaximumSellingPrice(maximumSellingPrice);
			getAgentSimulation().setMinimumProductQuality(minimumProductQuality);
			getAgentSimulation().setMaximumProductQuality(maximumProductQuality);
			
//			System.out.println("minimumSellingPrice: "+minimumSellingPrice);
//			System.out.println("maximumSellingPrice: "+maximumSellingPrice);
//			System.out.println("minimumProductQuality: "+minimumProductQuality);
//			System.out.println("maximumProductQuality: "+minimumProductQuality);
		}
		

		
		List<User> users=game.getUserList();
		if(users.size()>0){
			Double minimumImage=null;
			Double maximumImage=null;
			
			for(User user : users){
				Double image = user.getImageValue();

				if(minimumImage==null){
					minimumImage = image;
				}
				else if(image < minimumImage){
					minimumImage = image;
				}
				
				if(maximumImage==null){
					maximumImage = image;
				}
				else if(maximumImage < image){
					maximumImage = image;
				}
				
			}
			
			if(minimumImage==null || minimumImage<0.1)
				minimumImage=0.1;
			
			getAgentSimulation().setMinimumCompanyImage(minimumImage);
			getAgentSimulation().setMaximumCompanyImage(maximumImage);
			
			System.out.println("minimumImage: "+minimumImage);
			System.out.println("maximumImage: "+maximumImage);
		}
	}
	
	public List<Agent> generateAndAddAgentsByAgentType(List<AgentType> agentTypes,Setting setting){
		System.out.println("------ Generate Agents------");		
		AgentsSimulation as=getAgentSimulation();
		GaussianNumberGenerator gaussian = new GaussianNumberGenerator();
		Agent agent=null;
		for(AgentType agentType:agentTypes){
			for(int i=1;i<=agentType.getAmount();i++){
				agent=new Agent(agentType.getAgentName()+" - "+i);
				double preferencePrice=gaussian.getRandomGaussianValueRange(agentType.getMeanPrice(), setting.getPreferenceVariance(),0.0,1.0);
				double preferenceImage=gaussian.getRandomGaussianValueRange(agentType.getMeanImage(), setting.getPreferenceVariance(),0.0,1.0);
				double preferenceQuality=gaussian.getRandomGaussianValueRange(agentType.getMeanQuality(), setting.getPreferenceVariance(),0.0,1.0);
				agent.setPreferencePrice(preferencePrice);
				agent.setPreferenceImage(preferenceImage);
				agent.setPreferenceQuality(preferenceQuality);
				agent.setAgentType(agentType);
				as.addAgent(agent);
			}
		}
		
		return as.getAgents();
	}

	
//	public void getAgentInfo(){
//		List<Agent> agents=((AgentsSimulation)this.state).agents;
//		for(Agent a:agents){
//			System.out.println(a);
//		}
//	}

}
